#include "GError.h"
#include "GModule.h"
#include "GModuleManager.h"
#include "GModuleDescriptor.h"
#include "GDynamicLibrary.h"
#include "GInputModule.h"

// Remove after module linking system is implemented
#include "GRawInputModule.h"

namespace GEngine
{	
	//GModuleManager::DescriptorMap GModuleManager::Descriptors;

	GModuleManager::GModuleManager()
	{
	}

	GModuleManager::~GModuleManager()
	{
	}

	// Loads all dynamic modules at startup time
	bool GModuleManager::LoadLibraries(const char* FolderPath)
	{
		//! create a file iterator and load all library files in folder
		return true;
	}

	// Unloads all static + dynamic modules at uninitialize
	void GModuleManager::UnloadLibraries()
	{
		LibraryMap::iterator Iter = Libraries.begin();
		while (Iter != Libraries.end())
		{
			Iter->second->Unload();
			Iter->second->Destroy();
		}
		Libraries.clear();
	}

	// This method can be called even before ModuleManager is initialized.
	bool GModuleManager::RegisterModule(GModuleDescriptor* Descriptor)
	{
		//Do not make any checks except already exists.
		const char* DescName = Descriptor->GetName();

		DescriptorMap::iterator DescriptorIter = Descriptors.find(DescName);
		if (DescriptorIter != Descriptors.end())
		{
			// Already registered
			return true;
		}

		Descriptors.insert(DescriptorMap::value_type(DescName, Descriptor));

		return true;
	}

	void GModuleManager::UnregisterModule(GModuleDescriptor* Descriptor)
	{
		Descriptors.erase(Descriptor->GetName());
	}

	GModule* GModuleManager::CreateModule(const char* ModuleName)
	{
		GModuleDescriptor* Desc = GetDescriptor(ModuleName);
		
		// Check if we can create the instance
		bool CanCreate = (Desc != NULL) && (strcmp(Desc->GetImplemented(), "NULL") != 0);
		
		return CanCreate ? Desc->CreateInstance() : NULL;
	}

	GModuleDescriptor* GModuleManager::GetDescriptor(const char* ModuleName)
	{
		DescriptorMap::iterator DescriptorIter = Descriptors.find(ModuleName);

		return DescriptorIter == Descriptors.end() ? NULL : DescriptorIter->second;
	}

	const char* GModuleManager::GetImplementation(const char* InterfaceName, GSize Index)
	{
		GSize Count = 0;
		GSize FindId = Index + 1;

		const char* Implementation = NULL;
		DescriptorMap::iterator Iter = Descriptors.begin();
		while((FindId != Count) && (Iter != Descriptors.end()))
		{
			const char* Implemented = Iter->second->GetImplemented();
			bool Implements = strcmp(Implemented, InterfaceName) == 0;
			
			if (Implements)
			{
				Implementation = Iter->second->GetName();
				Count++;
			}

			Iter++;
		}

		return Implementation;
	}

	GUInt32 GModuleManager::GetImplementationCount(const char* InterfaceName)
	{
		GUInt32 Count = 0;

		DescriptorMap::iterator Iter = Descriptors.begin();
		while(Iter != Descriptors.end())
		{
			const char* Implemented = Iter->second->GetImplemented();
			bool Implements = strcmp(Implemented, InterfaceName) == 0;
			
			if (Implements)
			{
				Count++;
			}

			Iter++;
		}

		return Count;
	}

	bool GModuleManager::Initialize() OVERRIDE
	{
		if (!GInitializable::Initialize())
		{
			return false;
		}

		//! Get modules path from path manager
		bool Result = LoadLibraries("SomePath");
		if (!Result)
		{
			return false;
		}
		
		// Register engine interfaces by hand
		RegisterModule(GInputModule::Descriptor());


		// Temporarly register external modules by hand
		RegisterModule(GRawInput::GRawInputModule::Descriptor());

		return true;
	}

	void GModuleManager::Uninitialize() OVERRIDE
	{
		// All module instances should be released and destroyed at this moment
		UnloadLibraries();

		GInitializable::Uninitialize();
	}

}